package main

import (
	"context"
	"errors"
	conf "fitness/config"
	"fitness/internal"
	"fitness/internal/wechat"
	"fitness/pkg/db"
	"fitness/pkg/utils/R"
	"flag"
	"fmt"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"log"
	"net/http"
	"runtime/debug"
	"strconv"
)

func main() {
	var (
		config = flag.String("c", "./config.yaml", "config yaml")
	)
	flag.Parse()
	log.SetFlags(0)
	// 初始化日志配置
	logger := conf.NewLogger()
	//读取配置文件
	appConfig := conf.InitAppConfig(*config, logger)

	// 加载数据库配置
	dbConfig := conf.NewDBConfig(appConfig.DB)
	//设置数据
	gormDb, err := db.NewDB(dbConfig)
	if err != nil {
		log.Fatal("创建数据库失败~")
		return
	}

	// 配置Gin
	engine := gin.Default()
	engine.Use(CustomRecovery())
	//加载小程序配置
	wechatApp := wechat.NewMiniApp(appConfig.MiniApp, logger)
	//创建业务单例
	instance := internal.GetInstance(gormDb, logger, engine)
	//小程序请求service
	mpService := wechat.NewMpService(logger, instance, wechatApp)
	//小程序请求接口
	mp := wechat.NewMp(logger, mpService)

	mp.InitApiRouter(engine)
	//指定地址
	engine.Static("/static", "./static")
	// 启动 Modbus 轮询任务，在后台运行
	ctx, cancel := context.WithCancel(context.Background())

	defer cancel()

	engine.Static("/upload", "upload")

	// 注册全局404处理器
	engine.NoRoute(func(c *gin.Context) {
		c.JSON(http.StatusOK, R.ReturnFailMsg("接口不存在，请检查URL和请求方法"))
		c.Abort()
	})

	// 启动服务器
	logger.Info("服务启动", zap.Int("监听端口: ", appConfig.Svc.Port))
	// 启动 Gin 服务
	srv := &http.Server{
		Addr:    ":" + strconv.Itoa(appConfig.Svc.Port),
		Handler: engine, // 使用自定义的处理器
	}
	// 启动 Gin 服务在 goroutine 中运行，以便主 goroutine 可以等待它退出
	go func() {
		if err := srv.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) && err != nil {
			logger.Error("Gin 服务启动失败:", zap.Error(err))
			cancel() // 出错时也触发关闭
		}
	}()
	// 阻塞等待 Gin 退出
	<-ctx.Done()
}

// 自定义恢复中间件（修复日志输出问题）
func CustomRecovery() gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			if err := recover(); err != nil {
				// 正确的日志输出方式：使用 fmt.Fprintf 向 DefaultErrorWriter 写入
				fmt.Fprintf(gin.DefaultErrorWriter, "panic: %v\n", err)           // 错误信息
				fmt.Fprintf(gin.DefaultErrorWriter, "stack: %s\n", debug.Stack()) // 堆栈信息

				// 仅在响应未被写入时返回500
				if c.Writer.Status() == http.StatusOK {
					c.JSON(http.StatusOK, R.ReturnFailMsg("服务器内部错误"))
				}
				c.Abort()
			}
		}()
		c.Next()
	}
}
